package webServer

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

// 参考：https://go.dev/doc/articles/wiki/
type Page struct {
	Title string
	Body  []byte // 网页内容为什么会是 []byte，因为io库只接受 字节数组
}

func getFilePath(fileName string) string {
	return fileName + ".html_bin"
}

// Save 网页持久化
// 这样声明表示，此方法隶属于 结构体 Page
// 类似于java中对象的实例方法
func (p *Page) Save() error {
	fileName := getFilePath(p.Title)
	// 0644 在这里代表的是8进制
	return os.WriteFile(fileName, p.Body, 0644)
}

// LoadPage 从磁盘读取网页
func LoadPage(title string) (*Page, error) {
	fileName := getFilePath(title)
	pageBody, err := os.ReadFile(fileName)

	if err != nil {
		return nil, err
	}

	// 构建一个 Page 对象，然后返回这个对象的地址
	return &Page{Title: title, Body: pageBody}, nil
}

func GreetingsHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "hello, your uri path is %s", r.URL.Path[1:])
}

// 查看网页
func ViewHandler(w http.ResponseWriter, req *http.Request) {
	prefixLength := len("/view/")
	page, err := loadPageByRequestPath(req, prefixLength)

	title := parsePageTitle(req, prefixLength)

	if err != nil {
		// page 在本地不存在
		page = &Page{Title: title, Body: []byte("暂无内容")}
		page.Save()
	}
	fmt.Fprintf(w, renderHtml(
		page.Title,
		[]byte(fmt.Sprintf(`
		<h1>%s</h1>
		<br>
		<a href="/edit/%s">点我编辑</a>
		`, string(page.Body),
			page.Title))))

}

// 更新wiki时，表单中的的wiki内容的 key
const newPageContentKeyName = "newPageContent"

// 跳转编辑 html 网页
func EditHtmlPage(w http.ResponseWriter, req *http.Request) {

	page, err := loadPageByRequestPath(req, len("/edit/"))
	if err != nil {
		log.Fatal(err)
	}
	editArea := fmt.Sprintf(`
	<h1>Editing %s</h1>
        <form action="/save/%s" method="POST">
        <textarea name="%s">%s</textarea><br>
        <input type="submit" value="Save">
        </form>
	`, page.Title, page.Title, newPageContentKeyName, page.Body)
	fmt.Fprint(w, renderHtml(page.Title, []byte(editArea)))
}

// 保存网页
func SavePage(w http.ResponseWriter, req *http.Request) {

	newPageContent := req.FormValue(newPageContentKeyName)

	page := Page{Title: parsePageTitle(req, len("/save/")), Body: []byte(newPageContent)}

	page.Save()

	http.Redirect(w, req, "/view/"+page.Title, http.StatusFound)
	// ViewHandler(w, req)
}

// 从 request 从提取出请求路径，并返回从磁盘中加载到的 网页
func loadPageByRequestPath(req *http.Request, prefixLength int) (*Page, error) {

	pageTitle := parsePageTitle(req, prefixLength)

	return LoadPage(pageTitle)

}

// 从 request 中解析出 wiki 网页的名字
func parsePageTitle(req *http.Request, prefixLength int) string {
	return req.URL.Path[prefixLength:]
}

// 渲染 html 网页
func renderHtml(title string, body []byte) string {
	return fmt.Sprintf(`
	<html>
	<head>
		<title>%s</title>
	</hean>
	<body>
	%s
	</body>
	</html>
	`, title, body)
}
